namespace RB
{
namespace Math
{

#define ForEachMember(operation)        \
    for (uint32 ui=0; ui<Count; ++ui)   \
    {                                   \
        operation;                      \
    }                                   \

/***********************************************************************************************************
 * Empty Constructor
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
RBVector<Type, Count, RBVectorBaseType>::RBVector()
{

}

/***********************************************************************************************************
 * Scalar init
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
RBVector<Type, Count, RBVectorBaseType>::RBVector(Type scalar)
{
    *this = scalar;
}

/***********************************************************************************************************
 * Copy constructor
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
RBVector<Type, Count, RBVectorBaseType>::RBVector(const RBVector<Type, Count, RBVectorBaseType>& rhs)
{
    *this = rhs;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
RBVector<Type, Count, RBVectorBaseType>::RBVector(Type x, Type y)
{
    RBCompileAssert(Count == 2);
    this->Data[0] = x;
    this->Data[1] = y;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
RBVector<Type, Count, RBVectorBaseType>::RBVector(Type x, Type y, Type z)
{
    RBCompileAssert(Count == 3);
    this->Data[0] = x;
    this->Data[1] = y;
    this->Data[2] = z;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
RBVector<Type, Count, RBVectorBaseType>::RBVector(Type x, Type y, Type z, Type w)
{
    RBCompileAssert(Count == 4);
    this->Data[0] = x;
    this->Data[1] = y;
    this->Data[2] = z;
    this->Data[3] = w;
}


/***********************************************************************************************************
 * Destructor
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
RBVector<Type, Count, RBVectorBaseType>::~RBVector()
{

}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
const RBVector<Type, Count, RBVectorBaseType>& RBVector<Type, Count, RBVectorBaseType>::Zero()
{
    static const ThisType zero(0);
    return zero;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
Type RBVector<Type, Count, RBVectorBaseType>::operator()(int i) const
{
    return Data[i];
}
/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
Type& RBVector<Type, Count, RBVectorBaseType>::operator()(int i)
{
    return Data[i];
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
float32 RBVector<Type, Count, RBVectorBaseType>::Distance(const ThisType& point) const
{
    return (*this - point).GetLength();
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
Type RBVector<Type, Count, RBVectorBaseType>::SqrDistance(const ThisType& point) const
{
    return (*this - point).GetSqrLength();
}


/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
float32 RBVector<Type, Count, RBVectorBaseType>::GetLength() const
{
    return RBMath::Sqrt<float32>(GetSqrLength());
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
Type RBVector<Type, Count, RBVectorBaseType>::GetSqrLength() const
{
    return this->Dot(*this);
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
typename RBVector<Type, Count, RBVectorBaseType> RBVector<Type, Count, RBVectorBaseType>::Normalize() const
{
    float32 fInvLen = 1.0f / GetLength();
    return (*this) * fInvLen;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
Type RBVector<Type, Count, RBVectorBaseType>::Dot(const RBVector<Type, Count, RBVectorBaseType>& rhs) const
{
    Type out = 0;
    ForEachMember(out+= Data[ui] * rhs(ui));
    return out;
}


template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
typename RBVector<Type, Count, RBVectorBaseType> RBVector<Type, Count, RBVectorBaseType>::Cross( const ThisType& rhs ) const
{
    RBCompileAssert(Count == 3);
    RBVector<Type, Count, RBVectorBaseType> out;
    out(0) = Data[1] * rhs.Data[2] - Data[2] * rhs.Data[1];
    out(1) = Data[2] * rhs.Data[0] - Data[0] * rhs.Data[2];
    out(2) = Data[0] * rhs.Data[1] - Data[1] * rhs.Data[0];

    return out;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
typename RBVector<Type, Count, RBVectorBaseType> RBVector<Type, Count, RBVectorBaseType>::operator-() const
{
    RBVector<Type, Count, RBVectorBaseType> out;
    ForEachMember(out(ui) = -Data[ui]);
    return out;
}
/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
typename RBVector<Type, Count, RBVectorBaseType> RBVector<Type, Count, RBVectorBaseType>::operator+(const RBVector<Type, Count, RBVectorBaseType>& rhs) const
{
    RBVector<Type, Count, RBVectorBaseType> out;
    ForEachMember(out(ui) = Data[ui] + rhs(ui));
    return out;
}
/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
typename RBVector<Type, Count, RBVectorBaseType> RBVector<Type, Count, RBVectorBaseType>::operator-(const RBVector<Type, Count, RBVectorBaseType>& rhs) const
{
    RBVector<Type, Count, RBVectorBaseType> out;
    ForEachMember(out(ui) = Data[ui] - rhs(ui));
    return out;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
typename RBVector<Type, Count, RBVectorBaseType> RBVector<Type, Count, RBVectorBaseType>::operator*(Type scalar) const
{
    RBVector<Type, Count, RBVectorBaseType> out;
    ForEachMember(out(ui) = Data[ui] * scalar);
    return out;
}
/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
RBVector<Type, Count, RBVectorBaseType> operator*(Type scalar, const RBVector<Type, Count, RBVectorBaseType>& point)
{
    RBVector<Type, Count, RBVectorBaseType> out;
    ForEachMember(out(ui) = point(ui) * scalar);
    return out;
}
/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
typename RBVector<Type, Count, RBVectorBaseType> RBVector<Type, Count, RBVectorBaseType>::operator*(const RBVector<Type, Count, RBVectorBaseType>& rhs) const
{
    RBVector<Type, Count, RBVectorBaseType> out;
    ForEachMember(out(ui) = Data[ui] * rhs(ui));
    return out;
}
/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
typename RBVector<Type, Count, RBVectorBaseType>& RBVector<Type, Count, RBVectorBaseType>::operator=(const RBVector<Type, Count, RBVectorBaseType>& rhs)
{
    ForEachMember(Data[ui] = rhs(ui));
    return *this;
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
RBVector<Type, Count, RBVectorBaseType>& RBVector<Type, Count, RBVectorBaseType>::operator=(Type scalar)
{
    ForEachMember(Data[ui] = scalar);
    return *this;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
typename RBVector<Type, Count, RBVectorBaseType>& RBVector<Type, Count, RBVectorBaseType>::operator+=(const RBVector<Type, Count, RBVectorBaseType>& rhs)
{
    ForEachMember(Data[ui] += rhs(ui));
    return *this;
}
/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
typename RBVector<Type, Count, RBVectorBaseType>& RBVector<Type, Count, RBVectorBaseType>::operator-=(const RBVector<Type, Count, RBVectorBaseType>& rhs)
{
    ForEachMember(Data[ui] -= rhs(ui));
    return *this;
}
/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
typename RBVector<Type, Count, RBVectorBaseType>& RBVector<Type, Count, RBVectorBaseType>::operator*=(const RBVector<Type, Count, RBVectorBaseType>& rhs)
{
    ForEachMember(Data[ui] *= rhs(ui));
    return *this;
}
/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
typename RBVector<Type, Count, RBVectorBaseType>& RBVector<Type, Count, RBVectorBaseType>::operator*=(Type scalar)
{
    ForEachMember(Data[ui] *= scalar);
    return *this;
}


template<typename Type, uint32 Count, template<typename T, uint32 C> class RBVectorBaseType>
typename RBVector<Type, Count, RBVectorBaseType>& RBVector<Type, Count, RBVectorBaseType>::operator/=(Type scalar)
{
    float32 inv = 1.0f / scalar;
    ForEachMember(Data[ui] *= inv);
    return *this;
}

#undef ForEachMember
}
}